#!/usr/bin/perl -w
use warnings;
use strict;
use Getopt::Long qw(:config gnu_getopt);
## user modules
BEGIN {
    use File::Basename;
    my $program_path = File::Basename::dirname($0);
    push @INC, $program_path;
}
use FieldHash;

my $spec_bin1 = sub {
    my ($ic) = @_;
    return 1
        # reset current
        && $ic->{Idd_reset}     <= 0.2 # mA
        # display voltages
        && 1.4 <= $ic->{VDD18C_display}
        &&        $ic->{VDD18C_display} <= 2.3
        && $ic->{VCOMH_display} >= 2.5
        && $ic->{VCOML_display} <= -0.9
        && $ic->{VLCDC_display} >= 4
        && $ic->{VGHC_display}  >= 9
        && $ic->{VGLC_display}  <= -5
        && $ic->{Idd_display}   <= 8   # mA
        # RAM/register
        && $ic->{Register_read} eq 'P'
        && $ic->{RAM_cb}        eq 'P'
        && $ic->{RAM_one}       eq 'P'
        && $ic->{RAM_zero}      eq 'P'
        #&& $ic->{RAM_gs}        eq 'P'
        # dispay timing;
        && $ic->{DisplayTiming} eq 'P';
};

my $spec_bin2 = sub {
    my ($ic) = @_;
    return 1
        # reset current
        && $ic->{Idd_reset}     <= 0.2 # mA
        # display voltages
        && 1.4 <= $ic->{VDD18C_display}
        &&        $ic->{VDD18C_display} <= 2.3
        && $ic->{VCOMH_display} >= 2.5
        && $ic->{VCOML_display} <= -0.9
        && $ic->{VLCDC_display} >= 3.5 # differ
        && $ic->{VGHC_display}  >= 9
        && $ic->{VGLC_display}  <= -5
        && $ic->{Idd_display}   <= 8   # mA
        # RAM/register
        && $ic->{Register_read} eq 'P'
        && $ic->{RAM_cb}        eq 'P'
        && $ic->{RAM_one}       eq 'P'
        && $ic->{RAM_zero}      eq 'P'
        #&& $ic->{RAM_gs}        eq 'P'
        # dispay timing;
        && $ic->{DisplayTiming} eq 'P';
};

sub sort_bins {
    my ($ic) = @_;
    return 8 unless defined($ic);
    return 1 if $spec_bin1->($ic);
    return 2 if $spec_bin2->($ic);
    # reset current
    return 3 unless $ic->{Idd_reset}    <= 0.2; # mA
    # VDD18
    return 4 unless 1
        && 1.4 <= $ic->{VDD18C_display}
        &&        $ic->{VDD18C_display} <= 2.3;
    # RAM/register
    return 5 unless 1
        && $ic->{Register_read} eq 'P'
        && $ic->{RAM_cb}        eq 'P'
        && $ic->{RAM_one}       eq 'P'
        && $ic->{RAM_zero}      eq 'P';
    # display voltages
    return 6 unless 1
        && $ic->{VCOMH_display} >= 2.5
        && $ic->{VCOML_display} <= -0.9
        && $ic->{VLCDC_display} >= 3.5 # differ
        && $ic->{VGHC_display}  >= 9
        && $ic->{VGLC_display}  <= -5
        && $ic->{Idd_display}   <= 8;   # mA
    # dispay timing;
    return 7 unless $ic->{DisplayTiming} eq 'P';
    die("IMPOSSIBLE");
    #return 2; # bin-2
};

my $FS = ',';
my $MIN_DATA_ITEMS = 10;
my ($input, $output, $repository, $help);
my %options = (
    'input|i=s'      => \$input,
    'output|o=s'     => \$output,
    'repository|r=s' => \$repository,
    'help|h|?'       => \$help,
);
error(-1, "Please run the program with option '--help'.")
    unless (Getopt::Long::GetOptions(%options));
usage() if $help;

# =====================================================================

error(-1, "You must specify input file.") unless defined($input);
open INPUT, '<', $input or error(2, "cannot open input: $input: $!");
if (defined($output)) {
    open OUTPUT, '>', $output or error(3, "cannot open output: $output: $!");
    select OUTPUT;
}

tie my %hash, 'FieldHash';
{
    chomp(my $line = <INPUT>);
    my @name = split $FS, $line;
    (tied %hash)->name(\@name);
}

# =====================================================================
my @bins = map 0, 1 .. sort_bins();
while (<INPUT>) {
    next if (/^\s*\#\s/);
    chomp;
    my @data = split $FS;
    next unless @data >= $MIN_DATA_ITEMS;
    (tied %hash)->data(\@data);
    my $bin = sort_bins( \%hash );
    $bins[$bin] += 1;
    printf STDERR "[$bin] --> (%3d,%3d) [%4d]\n", $hash{Xadr}, $hash{Yadr}, $hash{ICWaf_No};
}

print "\n==== Summary ====\n";
for my $i (1 .. $#bins) {
    printf "Bin-$i: %4d\n", $bins[$i];
}

# =====================================================================

close INPUT;
close OUTPUT if defined($output);

# =====================================================================

sub usage {
    (my $PROG = $0) =~ s/.*[\\\/]//;
    print STDERR <<"EO_USAGE";
usage:
    $PROG [ OPTIONS ] -i INPUT -o OUTPUT
options:
    -i, --input=FILE   specify input file
    -o, --output=FILE  specify output file
    -h, --help         print this help screen
EO_USAGE
    exit 0 unless defined($_[0]);
    1;
}

sub error {
    my $exit_status = shift;
    my ($package, $filename, $line, $subroutine) = caller();
    $subroutine = 'main' unless defined($subroutine);
    print STDERR "$subroutine: ", @_, "\n";
    print STDERR "from: $filename +$line\n";
    exit $exit_status;
}

sub message {
    print STDERR @_, "\n";
    return 1;
}
